import datetime

from django.db import transaction
from django.db.models import F
from rest_framework import serializers
from rest_framework.serializers import ModelSerializer

from store.models import GoodsStock, GoodsTransferDetail, GoodsTransfer


class GoodsStockSerializer(ModelSerializer):
    """
    商品库存
    """
    goods_code = serializers.CharField(source='goods.code', read_only=True)
    goods_name = serializers.CharField(source='goods.name', read_only=True)
    goods_cate_name = serializers.CharField(source='goods.cate.name', read_only=True)
    goods_unit_name = serializers.CharField(source='goods.unit.name', read_only=True)
    goods_bar_code = serializers.CharField(source='goods.bar_code', read_only=True)
    goods_help_code = serializers.CharField(source='goods.help_code', read_only=True)
    house_name = serializers.CharField(source='house.name', read_only=True)
    supplier_name = serializers.CharField(source='supplier.name', read_only=True)
    total_amount = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = GoodsStock
        exclude = ["update_time", "add_time"]

    def get_total_amount(self, obj):
        return round(obj.price * obj.quantity, 2)


class GoodsTransferDetailSerializer(ModelSerializer):
    """
    调拨明细
    """
    id = serializers.IntegerField(required=False)
    goods_code = serializers.CharField(source='goods.code', read_only=True)
    goods_name = serializers.CharField(source='goods.name', read_only=True)
    goods_cate_name = serializers.CharField(source='goods.cate.name', read_only=True)
    goods_specs = serializers.CharField(source='goods.specs', read_only=True)
    goods_unit_name = serializers.CharField(source='goods.unit.name', read_only=True)
    transfer_code = serializers.CharField(source='transfer.code', read_only=True)
    transfer_time = serializers.CharField(source='transfer.transfer_time', read_only=True)
    out_house_name = serializers.CharField(source='transfer.out_house.name', read_only=True)
    in_house_name = serializers.CharField(source='transfer.in_house.name', read_only=True)
    user_name = serializers.CharField(source='transfer.user.real_name', read_only=True)

    class Meta:
        model = GoodsTransferDetail
        exclude = ["update_time", "add_time"]


class GoodsTransferSerializer(ModelSerializer):
    """
    商品调拨
    """
    user_name = serializers.CharField(source='user.real_name', read_only=True)
    out_house_name = serializers.CharField(source='out_house.name', read_only=True)
    in_house_name = serializers.CharField(source='in_house.name', read_only=True)
    oper_user_name = serializers.CharField(source='oper_user.real_name', read_only=True)
    details = GoodsTransferDetailSerializer(many=True, required=False)

    class Meta:
        model = GoodsTransfer
        exclude = ["add_time"]

    def create(self, validated_data):
        details = validated_data.pop('details')
        with transaction.atomic():
            # 创建事务保存点
            save_id = transaction.savepoint()
            instance = None
            try:
                instance = self.Meta.model.objects.create(**validated_data)
                create_list = [GoodsTransferDetail(transfer=instance, **d) for d in details]
                objs = GoodsTransferDetail.objects.bulk_create(create_list)
                for obj in objs:
                    self.update_goods(instance, obj, None)
            except Exception as e:
                print(e)
                transaction.savepoint_rollback(save_id)

            transaction.savepoint_commit(save_id)
        return instance

    def update(self, instance, validated_data):
        details = validated_data.pop('details')
        with transaction.atomic():
            # 创建事务保存点
            save_id = transaction.savepoint()
            try:
                instance.code = validated_data.get('code', instance.code)
                instance.transfer_time = validated_data.get('transfer_time', instance.transfer_time)
                instance.user = validated_data.get('user', instance.user)

                instance.out_house = validated_data.get('out_house', instance.out_house)

                old_in_house_id = instance.in_house_id

                instance.in_house = validated_data.get('in_house', instance.in_house)

                instance.total_amount = validated_data.get('total_amount', instance.total_amount)

                instance.remark = validated_data.get('remark', instance.remark)
                instance.oper_user = validated_data.get('oper_user', instance.oper_user)

                instance.save()

                for d in details:
                    _id = d.pop("id", None)
                    if _id:
                        org_obj = GoodsTransferDetail.objects.filter(id=_id).first()
                        org_obj.old_in_house_id = old_in_house_id
                        GoodsTransferDetail.objects.filter(id=_id).update(**d)
                        obj = GoodsTransferDetail.objects.filter(id=_id).first()
                    else:
                        org_obj = None
                        obj = GoodsTransferDetail.objects.create(transfer=instance, **d)

                    self.update_goods(instance, obj, org_obj)

            except Exception as e:
                print(e)
                transaction.savepoint_rollback(save_id)

            transaction.savepoint_commit(save_id)

        return instance

    def update_goods(self, instance, obj, org_obj):
        if org_obj is None:     # 增加
            # 增加新库存
            in_house_id = instance.in_house_id
            nums = GoodsStock.objects.filter(house_id=in_house_id, batch_num=obj.batch_num, goods_id=obj.goods_id)\
                .update(quantity=F("quantity") + obj.nums)
            if nums == 0:
                obj.house_id = in_house_id
                self.create_goods_stock(obj)
            # 减少原库存
            out_house_id = instance.out_house_id
            GoodsStock.objects.filter(house_id=out_house_id, batch_num=obj.batch_num, goods_id=obj.goods_id) \
                .update(quantity=F("quantity") - obj.nums)
        else:                   # 修改
            if org_obj.old_in_house_id != instance.in_house_id or org_obj.batch_num != obj.batch_num:
                # 减库存
                GoodsStock.objects.filter(house_id=org_obj.old_in_house_id, batch_num=org_obj.batch_num,
                                          goods_id=org_obj.goods_id) \
                    .update(quantity=F("quantity") - org_obj.nums)
                # 增加库存
                in_house_id = instance.in_house_id
                nums = GoodsStock.objects.filter(house_id=in_house_id, batch_num=obj.batch_num,
                                                 goods_id=obj.goods_id) \
                    .update(quantity=F("quantity") + obj.nums)
                if nums == 0:
                    obj.house_id = in_house_id
                    self.create_goods_stock(obj)
            else:
                GoodsStock.objects.filter(goods_id=obj.goods_id, house_id=instance.out_house_id,
                                          batch_num=obj.batch_num) \
                    .update(quantity=F("quantity") - obj.nums + org_obj.nums)

                GoodsStock.objects.filter(goods_id=obj.goods_id, house_id=instance.in_house_id,
                                          batch_num=obj.batch_num) \
                    .update(quantity=F("quantity") + obj.nums - org_obj.nums)

    def create_goods_stock(self, obj):
        data = {
            "goods_id": obj.goods_id,
            "house_id": obj.house_id,
            "batch_num": obj.batch_num,
            "specs": obj.goods.specs,
            "price": obj.price,
            "quantity": obj.nums
        }
        GoodsStock.objects.create(**data)
